<?php

/**
 * JPGraph v4.0.3
 */

namespace lemon\JpGraph\Image;

/**
 * @class RotImage
 * // Description: Exactly as Image but draws the image at
 * // a specified angle around a specified rotation point.
 */
class RotImage extends Image
{
	public $a	  = 0;
	public $dx	 = 0;
	public $dy	 = 0;
	public $transx = 0;
	public $transy = 0;
	private $m	 = [];

	public function __construct($aWidth, $aHeight, $a = 0, $aFormat = DEFAULT_GFORMAT, $aSetAutoMargin = true){
		parent::__construct($aWidth, $aHeight, $aFormat, $aSetAutoMargin);
		$this->dx = $this->left_margin + $this->plotwidth / 2;
		$this->dy = $this->top_margin + $this->plotheight / 2;
		$this->SetAngle($a);
	}

	public function SetCenter($dx, $dy){
		$old_dx   = $this->dx;
		$old_dy   = $this->dy;
		$this->dx = $dx;
		$this->dy = $dy;
		$this->SetAngle($this->a);

		return [$old_dx, $old_dy];
	}

	public function SetTranslation($dx, $dy){
		$old		  = [$this->transx, $this->transy];
		$this->transx = $dx;
		$this->transy = $dy;

		return $old;
	}

	public function UpdateRotMatrice(){
		$a = $this->a;
		$a *= M_PI / 180;
		$sa = sin($a);
		$ca = cos($a);
		// Create the rotation matrix
		$this->m[0][0] = $ca;
		$this->m[0][1] = -$sa;
		$this->m[0][2] = $this->dx * (1 - $ca) + $sa * $this->dy;
		$this->m[1][0] = $sa;
		$this->m[1][1] = $ca;
		$this->m[1][2] = $this->dy * (1 - $ca) - $sa * $this->dx;
	}

	public function SetAngle($a){
		$tmp	 = $this->a;
		$this->a = $a;
		$this->UpdateRotMatrice();

		return $tmp;
	}

	public function Circle($xc, $yc, $r){
		list($xc, $yc) = $this->Rotate($xc, $yc);
		parent::Circle($xc, $yc, $r);
	}

	public function FilledCircle($xc, $yc, $r){
		list($xc, $yc) = $this->Rotate($xc, $yc);
		parent::FilledCircle($xc, $yc, $r);
	}

	public function Arc($xc, $yc, $w, $h, $s, $e){
		list($xc, $yc) = $this->Rotate($xc, $yc);
		$s += $this->a;
		$e += $this->a;
		parent::Arc($xc, $yc, $w, $h, $s, $e);
	}

	public function FilledArc($xc, $yc, $w, $h, $s, $e, $style = ''){
		list($xc, $yc) = $this->Rotate($xc, $yc);
		$s += $this->a;
		$e += $this->a;
		parent::FilledArc($xc, $yc, $w, $h, $s, $e);
	}

	public function SetMargin($lm, $rm, $tm, $bm){
		parent::SetMargin($lm, $rm, $tm, $bm);
		$this->dx = $this->left_margin + $this->plotwidth / 2;
		$this->dy = $this->top_margin + $this->plotheight / 2;
		$this->UpdateRotMatrice();
	}

	public function Rotate($x, $y){
		// Optimization. Ignore rotation if Angle==0 || Angle==360
		if ($this->a == 0 || $this->a == 360) {
			return [$x + $this->transx, $y + $this->transy];
		}
		$x1 = round($this->m[0][0] * $x + $this->m[0][1] * $y, 1) + $this->m[0][2] + $this->transx;
		$y1 = round($this->m[1][0] * $x + $this->m[1][1] * $y, 1) + $this->m[1][2] + $this->transy;

		return [$x1, $y1];
	}

	public function CopyMerge($fromImg, $toX, $toY, $fromX, $fromY, $toWidth, $toHeight, $fromWidth = -1, $fromHeight = -1, $aMix = 100){
		list($toX, $toY) = $this->Rotate($toX, $toY);
		parent::CopyMerge($fromImg, $toX, $toY, $fromX, $fromY, $toWidth, $toHeight, $fromWidth, $fromHeight, $aMix);
	}

	public function ArrRotate($pnts){
		$n = safe_count($pnts) - 1;
		for ($i = 0; $i < $n; $i += 2) {
			list($x, $y)  = $this->Rotate($pnts[$i], $pnts[$i + 1]);
			$pnts[$i]	 = $x;
			$pnts[$i + 1] = $y;
		}

		return $pnts;
	}

	public function DashedLine($x1, $y1, $x2, $y2, $dash_length = 1, $dash_space = 4){
		list($x1, $y1) = $this->Rotate($x1, $y1);
		list($x2, $y2) = $this->Rotate($x2, $y2);
		parent::DashedLine($x1, $y1, $x2, $y2, $dash_length, $dash_space);
	}

	public function Line($x1, $y1, $x2, $y2){
		list($x1, $y1) = $this->Rotate($x1, $y1);
		list($x2, $y2) = $this->Rotate($x2, $y2);
		parent::Line($x1, $y1, $x2, $y2);
	}

	public function Rectangle($x1, $y1, $x2, $y2){
		// Rectangle uses Line() so it will be rotated through that call
		parent::Rectangle($x1, $y1, $x2, $y2);
	}

	public function FilledRectangle($x1, $y1, $x2, $y2){
		if ($y1 == $y2 || $x1 == $x2) {
			$this->Line($x1, $y1, $x2, $y2);
		} else {
			$this->FilledPolygon([$x1, $y1, $x2, $y1, $x2, $y2, $x1, $y2]);
		}
	}

	public function Polygon($pnts, $closed = false, $fast = false){
		// Polygon uses Line() so it will be rotated through that call unless
		// fast drawing routines are used in which case a rotate is needed
		if ($fast) {
			parent::Polygon($this->ArrRotate($pnts));
		} else {
			parent::Polygon($pnts, $closed, $fast);
		}
	}

	public function FilledPolygon($pnts){
		parent::FilledPolygon($this->ArrRotate($pnts));
	}

	public function Point($x, $y){
		list($xp, $yp) = $this->Rotate($x, $y);
		parent::Point($xp, $yp);
	}

	public function StrokeText($x, $y, $txt, $dir = 0, $paragraph_align = 'left', $debug = false){
		list($xp, $yp) = $this->Rotate($x, $y);

		return parent::StrokeText($xp, $yp, $txt, $dir, $paragraph_align, $debug);
	}
}
